package se.thoka.twt.client.json;

import java.util.Date;

import se.thoka.twt.client.json.JSONFieldParserUtil.Parser;

import com.google.gwt.json.client.JSONValue;
import com.gwtent.reflection.client.Field;

public class JSONPrimitivesParser implements JSONFieldParserUtil.Parser {
	
	private enum PrimParser implements Parser {
		STRING(String.class) {
			@Override
			public String parseNotNull(Field field, JSONValue value) {
				return value.isString().stringValue();
			}
		},
		DATE(Date.class) {
			@Override
			protected Date parseNotNull(Field field, JSONValue value) {
				String stringValue = value.isString().stringValue();
				@SuppressWarnings("deprecation")
				Date date = new Date(stringValue);
				return date;
			}
		},
		BOOLEAN(Boolean.class, boolean.class) {
			@Override
			protected Boolean parseNotNull(Field field, JSONValue value) {
				Boolean result = null;
				if (value.isBoolean() != null) {
					result = value.isBoolean().booleanValue();
				} else if (value.isString() != null) {
					result = Boolean.valueOf(value.isString().stringValue());
				} else {
					throw new IllegalArgumentException("BOOLEAN: Unable to pars value: " + value);
				}
				return result;
			}
		},
		DOUBLE(Double.class, double.class) {
			@Override
			protected Double parseNotNull(Field field, JSONValue value) {
				Double result = null;
				if (value.isNumber() != null) {
					result = value.isNumber().doubleValue();
				} else if (value.isString() != null) {
					result = Double.valueOf(value.isString().stringValue());
				} else {
					throw new IllegalArgumentException("DOUBLE: Unable to pars value: " + value);
				}
				return result;
			}
		},
		LONG(Long.class, long.class) {
			@Override
			protected Long parseNotNull(Field field, JSONValue value) {
				return ((Double) DOUBLE.parseNotNull(field, value)).longValue();
			}
		},
		INTEGER(Integer.class, int.class) {
			@Override
			protected Integer parseNotNull(Field field, JSONValue value) {
				return ((Double) DOUBLE.parseNotNull(field, value)).intValue();
			}
		},
		SHORT(Short.class, short.class) {
			@Override
			protected Object parseNotNull(Field field, JSONValue value) {
				return ((Double) DOUBLE.parseNotNull(field, value)).shortValue();
			}
		},
		CHARACTER(Character.class, char.class) {
			@Override
			protected Object parseNotNull(Field field, JSONValue value) {
				String str = value.isString().stringValue();
				return str.length() > 0 ? str.charAt(0) : "";
			}
		},
		;
		private final Class<?>[] clazzes;
		
		private PrimParser(Class<?>... clazzes) {
			this.clazzes = clazzes;
		}
		
		@Override
		public boolean accept(Field field) {
			boolean result = false;
			for (Class<?> clazz : clazzes) {
				if (JSONFieldParserUtil.isType(field.getType(), clazz)) {
					result = true;
					break;
				}
			}
			return result;
		}
		
		@Override
		public final Object parse(Field field, JSONValue value) {
			return TWTJSONParser.isNull(value) ? null : parseNotNull(field, value);
		}
		
		protected abstract Object parseNotNull(Field field, JSONValue value);
	}
	
	public JSONPrimitivesParser() {
	}
	
	@Override
	public boolean accept(Field field) {
		return getParser(field) != null;
	}

	@Override
	public Object parse(Field field, JSONValue value) {
		return getParser(field).parse(field, value);
	}

	private PrimParser getParser(Field field) {
		for (PrimParser parser : PrimParser.values()) {
			if (parser.accept(field)) {
				return parser;
			}
		}
		return null;
	}
}
